package net.ib.mtalk.ui.inbox;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import net.ib.mntalk.protocol.Common;
import net.ib.mntalk.protocol.Common.UUIDMsg;
import net.ib.mntalk.protocol.Common.UUIDSlicePredicate;
import net.ib.mntalk.protocol.Common.UUIDSliceRange;
import net.ib.mntalk.protocol.Common.UserBasicInfo;
import net.ib.mntalk.protocol.Common.ViewInfo;
import net.ib.mntalk.protocol.Session.CreateViewReq;
import net.ib.mntalk.protocol.Session.GetMembersReq;
import net.ib.mntalk.protocol.Session.GetViewsChangesReq;
import net.ib.mntalk.protocol.Session.GetViewsReq;
import net.ib.mntalk.protocol.Session.RemoveMembersReq;
import net.ib.mntalk.protocol.Session.SetViewPropertiesReq;
import net.ib.mntalk.protocol.client.Database.ReceiverList;
import net.ib.mtalk.R;
import net.ib.mtalk.database.DatabaseContract.ViewTable;
import net.ib.mtalk.database.helper.InboxDatabaseHelper;
import net.ib.mtalk.database.task.DBBackupHistoryMessagesTask;
import net.ib.mtalk.global.GlobalPreferences;
import net.ib.mtalk.network.NetResultReceiver;
import net.ib.mtalk.network.task.CreateViewTask;
import net.ib.mtalk.network.task.FileUploadTask;
import net.ib.mtalk.network.task.GetMembersTask;
import net.ib.mtalk.network.task.GetViewsChangesTask;
import net.ib.mtalk.network.task.GetViewsTask;
import net.ib.mtalk.network.task.RemoveMembersTask;
import net.ib.mtalk.network.task.RemoveViewTask;
import net.ib.mtalk.network.task.SetViewPropertiesTask;
import net.ib.mtalk.ui.UIController;
import net.ib.mtalk.ui.buddy.item.BuddyUUIDItem;
import net.ib.mtalk.ui.chat.ChatListActivity;
import net.ib.mtalk.ui.chat.ChatListBackgroundActivity;
import net.ib.mtalk.util.GpbSupport;
import net.ib.mtalk.util.MTalkLogWriter;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Handler;
import android.util.Log;

import com.google.protobuf.micro.InvalidProtocolBufferMicroException;

public class InboxController extends UIController {
	
	private NetResultReceiver mDeliverMessageReceiver;
	
	public InboxController(Context context, Handler handler){
		super(context, handler);
		mUiHandler = handler;
	}
	
	/**
	 * 1:1 채팅을 시작한다. 경우에 따라 CreateView를 호출 할 수 있다.
	 * @param cursor 버디 한명을 가르키는 커서이다.
	 * @throws InvalidProtocolBufferMicroException
	 * @throws IllegalArgumentException
	 */
	public void startOneToOneChat(long receiverMsb, long receiverLsb, String displayName){
		// TODO : 1. 뷰가 이미 만들어져 있는 지 확인
		//        2. 있을 경우 뷰에 들어간다.
		//        3. 없을 경우 뷰를 만들어준다.
		
		// 1. 뷰가 이미 만들어져 있는 지 확인

		// ViewTable에 이미 존재하는 데이터 인지 확인하기 위해서 ViewTable을 조회한다.
		String[] projection = new String[]{ ViewTable.KEY_CLIENT_VIEW_UUID_MSB, ViewTable.KEY_CLIENT_VIEW_UUID_LSB, ViewTable.KEY_VIEW_ENABLE };
		String selection = ViewTable.KEY_RECEIVER_UUID_MSB + "=?" + " AND " + ViewTable.KEY_RECEIVER_UUID_LSB + "=?";
		String[] selectionArgs = new String[] { String.valueOf(receiverMsb), String.valueOf(receiverLsb) };
		Cursor viewCursor = mContext.getContentResolver()
		.query(ViewTable.CONTENT_URI, projection, selection, selectionArgs, null);		
	
		try{
			// 채팅화면으로 넘어가기 위한 Intent를 설정한다.
			Intent intent = new Intent(mContext, ChatListBackgroundActivity.class);
			// 뷰가 반드시 하나만 존재해야 되므로(같은 뷰 일때는 새로운 뷰로 대체 되기때문) 첫번째 요소만 검사한다.
			if(viewCursor.moveToFirst()){
				// null 이 아닐 경우 View가 이미 존재한다는것을 확인.
				
				// 서버로 부터 응답(CreateVeiw)을 받은 View 인지를 확인 하기 위한 변수.
				int enable = viewCursor.getInt(viewCursor.getColumnIndexOrThrow(ViewTable.KEY_VIEW_ENABLE));
				// ViewTable에 등록 되어 있는 View를 불러온다.
				long clientViewUuidMsb = viewCursor.getLong(viewCursor.getColumnIndexOrThrow(ViewTable.KEY_CLIENT_VIEW_UUID_MSB));
				long clientViewUuidLsb = viewCursor.getLong(viewCursor.getColumnIndexOrThrow(ViewTable.KEY_CLIENT_VIEW_UUID_LSB));
				
				// 채팅시작을 위한 뷰 UUID를 설정한다. 
				// TODO : (DummyView 일 경우! 정상 뷰가 만들어졌을때 변경되어야 한다.!!)
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_MSB, clientViewUuidMsb);
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_LSB, clientViewUuidLsb);
				intent.putExtra(ChatListActivity.INTENT_EXIST_VIEW, true);
				// 서버와 연결된 View인지 확인
				if(enable == ViewTable.EnableType.DISABLE.ordinal()){
					// Dummy View 일때!(DISABLE 은 DummyView 를 뜻한다.)
					// Dummy View 일때는 존재하지 않는 뷰라고 명시한다.
					intent.putExtra(ChatListActivity.INTENT_ENABLE, enable);
					
					// 정상적인 뷰를 만들기 위해서 서버에 뷰 재생성 요청을 한다.
					CreateViewReq createViewReq = new CreateViewReq();
					UserBasicInfo userBasicInfo = new UserBasicInfo();
					userBasicInfo.setUserUuid(GpbSupport.makeUuidMsg(receiverMsb, receiverLsb));
					userBasicInfo.setDisplayName(displayName);
					createViewReq.addReceivers(userBasicInfo);
					createViewReq.setType(Common.ONE_TO_ONE);
					UUID clientViewUuid = new UUID(clientViewUuidMsb, clientViewUuidLsb);
					createView(createViewReq, clientViewUuid, true);
				}else{
					// DummyView가 아닌 정상적인 뷰라고 명시한다.
					intent.putExtra(ChatListActivity.INTENT_ENABLE, enable);								
				}
				mContext.startActivity(intent);
			}else{
				// ReceiverUUID 에 대한 View가 존재하지 않을 경우! 뷰를 다시 만들어준다.
				
				// 설정되어 있는 ViewUUID 가 없으므로 Dummy UUID 를 만든다.
				UUID clientViewUuid = UUID.randomUUID();
				long clientViewUuidMsb = clientViewUuid.getMostSignificantBits();
				long clientViewUuidLsb = clientViewUuid.getLeastSignificantBits();
				
				// 생성도 되지 않은 뷰이기 때문에 DummyView UUID 와 존재하지 않는 뷰라고 명시한다.
				intent.putExtra(ChatListActivity.INTENT_EXIST_VIEW, false);
				intent.putExtra(ChatListActivity.INTENT_ENABLE, ViewTable.EnableType.DISABLE.ordinal());
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_MSB, clientViewUuidMsb);
				intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_LSB, clientViewUuidLsb);
				
				// 뷰를 만들기 위해서 서버에 View 생성 요청을 한다.
				CreateViewReq createViewReq = new CreateViewReq();
				UserBasicInfo userBasicInfo = new UserBasicInfo();
				userBasicInfo.setUserUuid(GpbSupport.makeUuidMsg(receiverMsb, receiverLsb));
				userBasicInfo.setDisplayName(displayName);
				createViewReq.addReceivers(userBasicInfo);
				createViewReq.setType(Common.ONE_TO_ONE);
				createView(createViewReq, clientViewUuid, false);
				mContext.startActivity(intent);
			}
		}finally{
			viewCursor.close();
		}
	}
	
	public void startGroupChat(List<UserBasicInfo> receiverUuidList){
		startOtherChat(receiverUuidList, Common.GROUP_CHAT);
	}
	
	public void startInviteGroupChat(List<BuddyUUIDItem> items, ReceiverList receiverUuidList){
		List<UserBasicInfo> buddyUuidList = receiverUuidList.getReceiverList();
		for(BuddyUUIDItem item : items){
			UserBasicInfo userBasicInfo = new UserBasicInfo();
			userBasicInfo.setDisplayName(item.name);
			userBasicInfo.setUserUuid(GpbSupport.makeUuidMsg(item.msb, item.lsb));
			buddyUuidList.add(userBasicInfo);
		}
		startOtherChat(buddyUuidList, Common.GROUP_CHAT);
	}
	
	public void startBroadcastChat(List<UserBasicInfo> receiverUuidList){
		startOtherChat(receiverUuidList, Common.BROADCAST);
	}
	
	public void startOtherChat(List<UserBasicInfo> receiverUuidList, int chatType){
		// TODO : 1. 무조건 새로운 뷰를 만든다.
			
		Intent intent = new Intent(mContext, ChatListBackgroundActivity.class);

		// ReceiverUUID 에 대한 View가 존재하지 않을 경우! 뷰를 다시 만들어준다.
		
		// 설정되어 있는 ViewUUID 가 없으므로 Dummy UUID 를 만든다.
		UUID clientViewUuid = UUID.randomUUID();
		long clientViewUuidMsb = clientViewUuid.getMostSignificantBits();
		long clientViewUuidLsb = clientViewUuid.getLeastSignificantBits();
		
		// 생성도 되지 않은 뷰이기 때문에 DummyView UUID 와 존재하지 않는 뷰라고 명시한다.
		intent.putExtra(ChatListActivity.INTENT_EXIST_VIEW, false);
		intent.putExtra(ChatListActivity.INTENT_ENABLE, ViewTable.EnableType.DISABLE.ordinal());
		intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_MSB, clientViewUuidMsb);
		intent.putExtra(ChatListActivity.INTENT_CLIENT_VIEW_LSB, clientViewUuidLsb);
		
		// 뷰를 만들기 위해서 서버에 View 생성 요청을 한다.
		CreateViewReq createViewReq = new CreateViewReq();
		for(int i = 0; i < receiverUuidList.size(); i++){
			createViewReq.addReceivers(receiverUuidList.get(i));
		}
//		 자신을 설정한다.
//		UserBasicInfo userBasicInfo = new UserBasicInfo();
//		userBasicInfo.setUserUuid(GlobalPreferences.getUserUUID());
//		userBasicInfo.setDisplayName(GlobalPreferences.getUserName());
//		createViewReq.addReceivers(userBasicInfo);
		createViewReq.setType(chatType);
		createView(createViewReq, clientViewUuid, false);
		mContext.startActivity(intent);
	}
	
	/**
	 * SEVER API : CreateView
	 * View를 만듬 : 서버에 뷰생성 요청 -> 임시뷰 생성후 성공 리턴 -> 뷰 테이블에 뷰 생성.
	 * @param CreateViewReq - UUID, ChatType - 1:ONE_TO_ONE 2:MULTI 3:BROAD
	 * @param clientViewUuid viewUuid(existView or dummyView)
	 * @param isExist dummyView 인지 existView 인지 확인.
	 */
	public void createView(CreateViewReq createViewReq, UUID clientViewUuid, boolean isExist) {
		try{
			MTalkLogWriter.d("InboxController.createView()");
			CreateViewTask task = new CreateViewTask(mContext, mUiHandler, createViewReq, clientViewUuid, isExist);
			task.execute();
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}
	
	/**
	 * 서버로 부터 모든 뷰를 받아온다.
	 * @author happy2v
	 */
	public void getAllViews(){
		UUIDSliceRange slice_range = new UUIDSliceRange();
		slice_range.setAscending(true);
		slice_range.setMaxCount(InboxListActivity.GET_VIEWS_COUNT);
		UUIDSlicePredicate predicate = new UUIDSlicePredicate();
		predicate.setSliceRange(slice_range);
		GetViewsReq getViewsReq = new GetViewsReq();
		getViewsReq.setPredicate(predicate);
		try{
			MTalkLogWriter.d("InboxController.getViews()");
			GetViewsTask task = new GetViewsTask(mContext, mUiHandler, getViewsReq);
			task.execute();
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}
	
	/**
	 * 기본 ViewNoti를 설정해주기위해 한번 요청을한다.
	 * @author happy2v
	 */
	public void getViewChangeForNoti(){
		try{
			UUIDSliceRange range = new UUIDSliceRange();
//			range.setStart(GlobalPreferences.getLastViewChangedNotiUUID());
			range.setAscending(false);
			range.setMaxCount(10);
			GetViewsChangesReq getViewsChangesReq = new GetViewsChangesReq();
			getViewsChangesReq.setRange(range);
			GetViewsChangesTask task = new GetViewsChangesTask(mContext, mUiHandler, getViewsChangesReq);
			task.execute();
		} catch(Exception e){
			MTalkLogWriter.e(e);
		}
	}
	
	/**
	 * 기본 ViewNoti를 설정해주기위해 한번 요청을한다.
	 * @author happy2v
	 */
	public void getViewChangeTest(){
		try{
			UUIDSliceRange range = new UUIDSliceRange();
//			range.setStart(GlobalPreferences.getLastViewChangedNotiUUID());
			range.setAscending(false);
			range.setMaxCount(10);
			GetViewsChangesReq getViewsChangesReq = new GetViewsChangesReq();
			getViewsChangesReq.setRange(range);
			GetViewsChangesTask task = new GetViewsChangesTask(mContext, mUiHandler, getViewsChangesReq);
			task.execute();
		} catch(Exception e){
			MTalkLogWriter.e(e);
		}
	}
	
	public int getChatType(long clientViewUuidMsb, long clientViewUuidLsb){
		return InboxDatabaseHelper.getChatType(mContext, clientViewUuidMsb, clientViewUuidLsb);
	}
	
	/**
	 * 푸시 상태를 업데이트 한다.
	 * (PreExecute 에서 null 을 리턴해서 네트워크 작업을 하지 않는다.)
	 * @param pushState
	 * @param clientViewUuidMsb
	 * @param clientViewUuidLsb
	 */
	public void updateViewPush(int pushState, long clientViewUuidMsb, long clientViewUuidLsb){
		try{
			boolean pushAllowed = true;
			if(pushState == ViewTable.PushType.ON.ordinal()){
				pushAllowed = true;
			}else if(pushState == ViewTable.PushType.OFF.ordinal()){
				pushAllowed = false;
			}
			
			ViewInfo viewInfo = InboxDatabaseHelper.getViewInfo(mContext, clientViewUuidMsb, clientViewUuidLsb);
			viewInfo.setPushAllowed(pushAllowed);
			
			SetViewPropertiesReq setViewPropertiesReq = new SetViewPropertiesReq();
			setViewPropertiesReq.setView(viewInfo);
			setViewPropertiesReq.addProperty(Common.PUSH_ALLOWED);
			
			SetViewPropertiesTask task = new SetViewPropertiesTask(mContext, mUiHandler, setViewPropertiesReq);
			task.execute();
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}
	
	/**
	 * 타이틀을 변경한다.
	 * @param title
	 * @param clientViewUuidMsb
	 * @param clientViewUuidLsb
	 */
	public void updateViewTitle(String title, long clientViewUuidMsb, long clientViewUuidLsb){
		try{
			ViewInfo viewInfo = InboxDatabaseHelper.getViewInfo(mContext, clientViewUuidMsb, clientViewUuidLsb);
			viewInfo.setTitle(title);
			
			SetViewPropertiesReq setViewPropertiesReq = new SetViewPropertiesReq();
			setViewPropertiesReq.setView(viewInfo);
			setViewPropertiesReq.addProperty(Common.TITLE);
			
			SetViewPropertiesTask task = new SetViewPropertiesTask(mContext, mUiHandler, setViewPropertiesReq);
			task.execute();
		}catch(Exception e){
			MTalkLogWriter.e(e);
		}
		
	}
	
	/**
	 * 데이터 베이스에서 메시지를 읽어와서 메일 내용에 적고 sendmail 인텐트를 호출한다.
	 * (PreExecute 에서 null 을 리턴해서 네트워크 작업을 하지 않는다.)
	 * @param clientViewUuid
	 */
	public void backupHistoryMessage(UUID clientViewUuid){
		try{
			MTalkLogWriter.d("InboxController.backupHistoryMessage()");
			DBBackupHistoryMessagesTask task = new DBBackupHistoryMessagesTask(mContext, mUiHandler, clientViewUuid);
			task.execute();
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}
	
	
	/**
	 * 채팅방을 나간다.
	 * @param clieUuidvUuid
	 */
	public void leaveChat(UUID clientViewUuid){
		try{
			MTalkLogWriter.d("InboxController.leaveChat()");
			UserBasicInfo userBasicInfo = new UserBasicInfo();
			userBasicInfo.setDisplayName(GlobalPreferences.getUserName());
			userBasicInfo.setUserUuid(GlobalPreferences.getUserUUID());
			
			RemoveMembersReq removeMembersReq = new RemoveMembersReq();
			removeMembersReq.setViewUuid(InboxDatabaseHelper.getViewUUID(mContext, clientViewUuid));
			removeMembersReq.addReceiverInfo(userBasicInfo);
			
			RemoveMembersTask task = new RemoveMembersTask(mContext, mUiHandler, removeMembersReq, clientViewUuid, ViewTable.EnableType.LEAVE.ordinal());
			task.execute();
		}catch(Exception e){
			MTalkLogWriter.e(e);
		}
	}
	
	/**
	 * 뷰 삭제 : 서버 삭제요청 -> 삭제 완료 -> 데이터베이스 삭제
	 * @param clientViewUuidList 클라이언트에서 만들어진 UUID 리스트
	 * @param viweUuid 서버에서 생성완료된 UUID 리스트
	 */
	public void deleteView(List<UUID> clientViewUuidList, List<UUIDMsg> viewUuidList){
		try{
			MTalkLogWriter.d("InboxController.updateViewPush()");
			RemoveViewTask task = new RemoveViewTask(mContext, mUiHandler, clientViewUuidList, viewUuidList);
			task.execute();
		} catch(Exception e) {
			MTalkLogWriter.e(e);
		}
	}
	
	public void deleteViewGroup(final long clientViewUuidMsb, final long clientViewUuidLsb){
		new AlertDialog.Builder(mContext)
		.setMessage(R.string.delete_group_chat)
		.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		})
		.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				leaveChat(GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb));
				List<UUID> clientViewUuidList = new ArrayList<UUID>();
				clientViewUuidList.add(GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb));
				deleteView(clientViewUuidList, null);
				dialog.dismiss();
			}
		})
		.create()
		.show();
	}
	
	public void deleteViewBroadcast(final long clientViewUuidMsb, final long clientViewUuidLsb){
		new AlertDialog.Builder(mContext)
		.setMessage(R.string.delete_broadcast_chat)
		.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		})
		.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				List<UUID> clientViewUuidList = new ArrayList<UUID>();
				clientViewUuidList.add(GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb));
				deleteView(clientViewUuidList, null);
				dialog.dismiss();
			}
		})
		.create()
		.show();
	}
	
	public void deleteViewOnetoone(final long clientViewUuidMsb, final long clientViewUuidLsb){
		new AlertDialog.Builder(mContext)
		.setMessage(R.string.delete_one_to_one)
		.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		})
		.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				List<UUID> clientViewUuidList = new ArrayList<UUID>();
				clientViewUuidList.add(GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb));
				deleteView(clientViewUuidList, null);
				dialog.dismiss();
			}
		})
		.create()
		.show();
	}
}
